<template>
  <el-form
    class="form-container"
    ref="ruleFormRef"
    :model="form"
    :label-width="labelWidth"
    :style="{ width: size }"
  >
    <el-row :align="'middle'" :justify="'center'">
      <template v-for="item in formItems">
        <el-col v-bind="itemColLayout">
          <el-form-item
            :label="item.label"
            :prop="item.prop"
            :style="{
              itemStyle: true,
              alignItems: item.type !== 'upload' ? 'center' : 'top',
            }"
            :rules="item.rules"
          >
            <el-input
              v-if="item.type == 'number'"
              v-model="form[`${item.prop}`]"
              oninput="if(value.length > 11) value=value.slice(0, 11)"
              :type="item.type"
              :disabled="item.disabled"
              :placeholder="`请输入${item.label}`"
              v-bind="item.otherOptions"
              onkeypress="return /[\d]/.test(String.fromCharCode(event.keyCode))"
            />
            <el-input
              v-if="
                item.type == 'input' ||
                item.type == 'textarea' ||
                item.type == 'password'
              "
              v-model="form[`${item.prop}`]"
              :type="item.type"
              :disabled="item.disabled"
              :maxlength="item.maxlength"
              :show-word-limit="item.showWordLimit"
              :placeholder="`请输入${item.label.replace('：', '')}`"
              :show-password="item.type === 'password'"
              v-bind="item.otherOptions"
            />
            <!-- 下拉筛选 -->
            <el-select
              v-if="item.type == 'select'"
              v-model="form[`${item.prop}`]"
              v-bind="item.otherOptions"
              style="width: 100%"
              :placeholder="`请选择${item.label.replace('：', '')}`"
              :disabled="item.disabled"
            >
              <el-option
                v-for="option in optionItem[`${item.prop}`] || item.valueEnum"
                :key="option.key"
                :label="option.value"
                :value="option.key"
              ></el-option>
            </el-select>
            <!-- 日期 -->
            <el-date-picker
              v-if="item.type == 'datepicker'"
              v-model="form[`${item.prop}`]"
              v-bind="item.otherOptions"
              placeholder="请选择日期"
              :disabled="item.disabled"
            ></el-date-picker>

            <!-- 上传 -->
            <div v-if="item.type == 'upload'" style="width: 100%">
              <el-upload
                class="upload-demo"
                drag
                ref="upload"
                :limit="1"
                v-model="form[`${item.prop}`]"
                :before-upload="beforeUpload"
                :on-exceed="handleExceed"
                :on-remove="
                  (uploadFile, uploadFileList) =>
                    handleRemove(uploadFile, uploadFileList, item)
                "
                :http-request="(option: any) => requestUpload(option, item)"
                :on-change="handleProgress"
              >
                <el-icon class="el-icon--upload"><upload-filled /></el-icon>
                <div class="el-upload__text">
                  <em>点击</em>
                  或将文件
                  <em>拖拽</em>
                  到这里上传
                </div>
                <template #tip>
                  <div class="el-upload__tip">请上传xls或者xlsx的文件</div>
                </template>
              </el-upload>
              <el-progress v-if="showProcess" :percentage="processLen" />
            </div>
          </el-form-item>
        </el-col>
      </template>
    </el-row>
    <div class="footer" v-if="showSubmit">
      <slot name="footer">
        <el-button type="primary" @click="resetBtnClick">重置</el-button>
        <el-button
          type="primary"
          :loading="loading"
          @click="searchBtnClick(ruleFormRef)"
        >
          提交
        </el-button>
      </slot>
    </div>
  </el-form>
</template>

<script setup lang="ts">
import { RuleItem } from "async-validator";
import { delEmpty } from "@/utils/delEmpty";
import {
  FormInstance,
  UploadFile,
  UploadFiles,
  UploadInstance,
  UploadProps,
  UploadRawFile,
  UploadRequestOptions,
} from "element-plus";
import { UploadAjaxError } from "element-plus/es/components/upload/src/ajax";
import { StyleValue } from "vue";
// import { uploadFileList } from "@/api/dashboard";
const showProcess = ref(false);
const processLen = ref(0);
const upload = ref<UploadInstance>();
const ruleFormRef = ref<FormInstance>();
interface FormItems {
  label?: string;
  type?: string;
  placeholder?: string;
  rules?: RuleItem;
  prop?: string;
  valueEnum?: Object;
  clearable?: boolean;
  maxlength?: number;
  disabled?: boolean;
  multiple?: boolean;
  uploadRequest?: () => Promise<any[]>;
  optionList?: () => Promise<any[]>;
  width?: number;
  otherOptions?: any;
  callback?: (props: any) => void;
}

const props = withDefaults(
  defineProps<{
    formItems: Array<FormItems | any>;
    labelWidth?: string;
    itemColLayout?: object;
    itemStyle?: StyleValue;
    uploadRequest?: any;
    showSubmit?: boolean;
    size?: string;
    request: any;
    callback?: (props: any) => void;
  }>(),
  {
    labelWidth: "100px",

    showSubmit: true,
    itemStyle: () => ({
      padding: "0",
    }),
  },
);

const formParams = computed(() => {
  let params: any = {};
  props.formItems.map((item) => {
    params[item.prop] = item.value ?? "";
    if (item.type == "upload") {
      params[item.prop] = item.value ?? "";
    }
  });
  return params;
});
const form = reactive({ ...formParams.value });
const optionItem = reactive<any>({});
const handleExceed: UploadProps["onExceed"] = (files: any, fileList: any) => {};
// 文件移除
const handleRemove = (
  uploadFile: UploadFile,
  uploadFiles: UploadFiles,
  item: any,
) => {
  showProcess.value = false;

  // const index = form[item.prop].findIndex(
  //   (it: any) => it.uid == uploadFile.uid
  // );
  form[item.prop] = "";
};
// 上传之前的判断
const beforeUpload = (rawFile: UploadRawFile) => {
  const { name } = rawFile;
  const arr = name.split(".");
  const afterName = arr[arr.length - 1];
  if (afterName !== "xls" && afterName !== "xlsx") {
    showProcess.value = false;
    ElMessage.error("请输入正确的格式（.xls或者.xlsx文件）");
    return false;
  }

  return true;
};
// 进度条
const handleProgress = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
  if (uploadFile.status == "ready") {
    processLen.value = 0;
    showProcess.value = true;
    const interval = setInterval(() => {
      if (processLen.value >= 99) {
        clearInterval(interval);
        return;
      }
      processLen.value += 1;
    }, 80);
  }
  if (uploadFile.status == "success" || uploadFile.status == "fail") {
    processLen.value = 100;
    showProcess.value = false;
  }
};
const removeFile = (name: string, field: string) => {
  const idx =
    form[field] && form[field].findIndex((item: any) => item.name == name);
  form[field].splice(idx, 1);
};

const uploadMethods = (
  file: File,
  field: any,
  onError?: (res: UploadAjaxError) => void,
) => {
  return props
    .uploadRequest({ file: file })
    .then((res: any) => {
      if (res.errno == 0 || res.errno == 200) {
        form[field] = res?.data;
        ElMessage.success("文件上传成功");
      }
    })
    .catch((err: any) => {
      onError && onError(err);
      removeFile(file.name, field);
      ElMessage.error("文件上传失败，请筛选时间并进行上传！");
    });
};

// 请求接口
const requestUpload = (options: UploadRequestOptions, item: any) => {
  const { onError, file } = options;
  // const fileInfo: any = file;

  // form[item.prop].push({ uid: fileInfo.uid, name: fileInfo.name });
  // console.log("’12345676", form[item.prop]);

  return uploadMethods(file, item.prop, onError);
};
const loading = ref(false);
// 提交按钮
const searchBtnClick = async (formEl: FormInstance | undefined) => {
  if (props.showSubmit) {
    if (!formEl) return;
    await formEl.validate((valid, fields) => {
      if (valid) {
        const handleForm = delEmpty(form);
        if (JSON.stringify(handleForm) == "{}") return;
        loading.value = true;

        props.request &&
          props
            .request(form)
            .then(() => {
              loading.value = false;
              props.callback && props.callback({ success: "ok" });
            })
            .finally(() => (loading.value = false));
      } else {
        console.log("error submit!", valid, fields);
        loading.value = false;
      }
    });
  } else {
    return await props.request(form).then(() => {
      loading.value = false;
      props.callback && props.callback({ success: "ok" });
    });
  }
};
// 获取下拉数据
const getOptionList = () => {
  props.formItems.map(async (item) => {
    if (!item.optionList) return;
    optionItem[item.prop] = [];
    const res = await item.optionList!();
    optionItem[item.prop].push(...res);
  });
};
getOptionList();

// 重置按钮
const resetBtnClick = () => {
  ruleFormRef.value?.resetFields();
};
defineExpose({ searchBtnClick, ruleFormRef, loading, processLen });
</script>

<style lang="scss">
@media screen and (max-width: 1700px) {
  .form-container {
    width: 90% !important;
  }
}
.el-popper {
  transform-origin: left top;
  transform: scale(var(--scale));
}
.form-container {
  margin: 0 auto 18px;
  .el-input {
    height: 40px;
  }
  .upload-demo {
    width: 100%;
  }
}
.footer {
  text-align: right;
}
.el-upload-dragger .el-icon--upload {
  color: var(--el-color-primary);
}
.el-progress__text {
  color: #000;
}
.el-dialog .el-select .el-input .el-select__caret {
  color: #000 !important;
}
input::placeholder {
  color: rgb(168, 171, 178) !important;
}
.el-form .el-input__prefix {
  color: rgb(168, 171, 178);
}
.el-form .el-input__wrapper {
  height: 100%;
}
</style>
